using CriWare;
using CriWare.CriMana;
using Cysharp.Threading.Tasks;
using System;
using UnityEngine;

namespace IQIGame.Onigao.Game
{

    public abstract class VideoPlayerBase : IDisposable
    {
        protected CriManaMovieMaterial _rawVideoPlayer;
        public CriManaMovieMaterial rawVideoPlayer => this._rawVideoPlayer;

        protected AutoResetUniTaskCompletionSource _playVideoTaskSource;

        public bool ApplyTargetAlpha { private set; get; }
        public bool AdditiveMode { private set; get; }

        public bool IsPlayerEnd
        {
            get
            {
                var status = _rawVideoPlayer.player.status;
                switch (status)
                {
                    case Player.Status.Stop:
                    case Player.Status.PlayEnd:
                        return true;
                }
                return false;
            }
        }

        public bool IsPlaying => !IsPlayerEnd;

        /// <summary>
        /// 使用完毕，需要释放
        /// </summary>
        public virtual bool needReturnPool { get; private set; } = false;

        //循环播放
        bool m_loopSeekEnable;
        //循环播放-开始帧
        uint m_loopSeekStartFrame;
        //循环播放-结束帧
        uint m_loopSeekEndFrame;


        public void InitPlayer(Transform root, bool isApplyTargetAlpha, bool isAdditiveMode)
        {
            if (_rawVideoPlayer == null)
            {
                _rawVideoPlayer = CreateRawPlayer(root, isApplyTargetAlpha, isAdditiveMode);
                ApplyTargetAlpha = _rawVideoPlayer.applyTargetAlpha;
                AdditiveMode = _rawVideoPlayer.additiveMode;
            }

            // 设置音量
            //float volume;
            //if (AudioManager.Instance.IsMute(AudioVolumeType.Sfx))
            //{
            //    volume = 0;
            //}
            //else
            //{
            //    volume = AudioManager.Instance.GetVolume(AudioVolumeType.Sfx);
            //}
            //moviePlayer.player.SetVolume(volume);

        }

        protected abstract CriManaMovieMaterial CreateRawPlayer(Transform root, bool applyTargetAlpha, bool additiveMode);

        protected abstract bool CheckVideoTarget();

        public CriManaMovieMaterial GetRawPlayer()
        {
            return _rawVideoPlayer;
        }



        public UniTask Play(string videoPath, bool loop = false, float speed = 1)
        {
            if (!CheckVideoTarget())
            {
                Debug.LogWarning($"{nameof(VideoPlayerBase)}.target is null, please call SetVideoTarget first.");
                return UniTask.CompletedTask;
            }
            var path = FrameworkPath.GetVideoFilePath(videoPath);
            _rawVideoPlayer.player.Stop();
            _rawVideoPlayer.player.SetFile(null, path, Player.SetMode.New);

            if (!IsPlayerEnd)
            {
                return UniTask.CompletedTask;
            }

            if (_playVideoTaskSource != null)
            {
                // 注意！这里要先置空，再调用，TrySetResult会先调用await之后的代码，如果await之后有给TaskSource赋新值，然后这里再置空，那么_completeActTaskSource就永远为null了。
                // 若置空不及时导致了多次source.TrySetResult，会导致池内数据异常
                var source = _playVideoTaskSource;
                _playVideoTaskSource = null;
                source.TrySetCanceled();
            }
            _playVideoTaskSource = AutoResetUniTaskCompletionSource.Create();

            //由于在第一次播放设置moviePlayer.player.Loop(loop)无效，并且moviePlayer.loop无法在播放过后再修改，所以这样调用
            _rawVideoPlayer.player.Loop(loop);

            _rawVideoPlayer.player.SetSpeed(speed);
            _rawVideoPlayer.Play();
            //_rawVideoPlayer.player.Start();

            return _playVideoTaskSource.Task;
        }

        /// <summary>
        ///  Seek模式，循环播放其中的一段
        /// </summary>
        /// <param name="startFrame">开始帧</param>
        /// <param name="endFrame">结束帧</param>
        /// <param name="immediateSeekStart">立即seek</param>
        public void SetLoopSeek(uint startFrame, uint endFrame, bool immediateSeekStart)
        {
            if (startFrame >= endFrame)
            {
                Debug.LogWarning($"[MovieManager] startFrame({startFrame}) is no less than endFrame({endFrame}).");
                return;
            }

            if (_rawVideoPlayer.player.movieInfo != null)
            {
                var totalFrames = _rawVideoPlayer.player.movieInfo.totalFrames;

                if (startFrame > totalFrames)
                {
                    Debug.LogWarning($"[MovieManager] startFrame({startFrame}) is greater than totalFrames({totalFrames}).");
                    return;
                }
                if (endFrame > totalFrames)
                {
                    Debug.LogWarning($"[MovieManager] endFrame({endFrame}) is greater than totalFrames({totalFrames}).");
                    return;
                }
            }

            m_loopSeekEnable = true;
            m_loopSeekStartFrame = startFrame;
            m_loopSeekEndFrame = endFrame;

            //立即从seek到起始帧
            if (immediateSeekStart)
            {
                _rawVideoPlayer.player.SetSeekPosition((int)startFrame);
                _rawVideoPlayer.player.Start();
            }
        }


        public virtual void OnUpdate(float deltaTime)
        {

            if (_rawVideoPlayer.player.frameInfo != null)
            {
                //循环播放
                if (m_loopSeekEnable)
                {
                    var status = _rawVideoPlayer.player.status;
                    if ((status == Player.Status.Playing || status == Player.Status.PlayEnd) && _rawVideoPlayer.player.frameInfo.frameNo >= m_loopSeekEndFrame)
                    {
                        _rawVideoPlayer.player.SetSeekPosition((int)m_loopSeekStartFrame);
                        _rawVideoPlayer.player.Start();
                    }
                }
            }

            if (IsPlayerEnd)
            {
                // 检测播放结束
                if (_playVideoTaskSource != null)
                {
                    // 注意！这里要先置空，再调用，TrySetResult会先调用await之后的代码，如果await之后有给TaskSource赋新值，然后这里再置空，那么_completeActTaskSource就永远为null了。
                    // 若置空不及时导致了多次source.TrySetResult，会导致池内数据异常
                    var source = _playVideoTaskSource;
                    _playVideoTaskSource = null;
                    source.TrySetResult();
                }
            }

        }

        /// <summary>
        /// 停止Seek模式视频循环
        /// </summary>
        public void CancelLoopSeek()
        {
            m_loopSeekEnable = false;
        }

        public void PauseVideo()
        {
            if (IsPlayerEnd)
            {
                return;
            }

            _rawVideoPlayer.player.Pause(true);
        }

        public void ResumeVideo()
        {
            if (IsPlayerEnd)
            {
                return;
            }

            _rawVideoPlayer.player.Pause(false);
        }

        /// <summary>
        /// 停止视频
        /// </summary>
        /// <param name="taskComplete">设置任务完成的状态</param>
        /// <param name="releasePlayer">是否释放Player</param>
        public void StopVideo(bool taskComplete = false, bool releasePlayer = true)
        {
            _rawVideoPlayer.player.Stop();

            if (_playVideoTaskSource != null)
            {
                var source = _playVideoTaskSource;
                _playVideoTaskSource = null;
                if (taskComplete)
                {
                    source.TrySetResult();
                }
                else
                {
                    source.TrySetCanceled();
                }
            }

            if (releasePlayer)
            {
                // 设置标记等待释放
                needReturnPool = true;
            }
        }


        //当前时间
        public float GetTime()
        {
            var player = _rawVideoPlayer.player;
            if (player.frameInfo == null)
                return 0;
            return (float)player.frameInfo.frameNo / player.frameInfo.framerateN / player.frameInfo.framerateD * 1000000.0f;
        }

        //总时长
        public float GetTotalTime()
        {
            var player = _rawVideoPlayer.player;
            if (player.movieInfo == null)
                return 0;
            var totalFrames = player.movieInfo.totalFrames;
            var frameRate = player.movieInfo.framerateN;
            return totalFrames * 1000.0f / frameRate;
        }

        public virtual void OnReset()
        {
            if (_rawVideoPlayer != null)
            {
                _rawVideoPlayer.enabled = false;
            }

            if (_playVideoTaskSource != null)
            {
                var source = _playVideoTaskSource;
                _playVideoTaskSource = null;
                source.TrySetCanceled();
            }

            needReturnPool = false;

            m_loopSeekEnable = false;
            //m_loopSeekStartFrame = 0;
            //m_loopSeekEndFrame = 0;
            //m_requestedSeekFrame = 0;

        }

        void ResetFadeInOut()
        {

            //m_onFadeOut = null;

            //fadeOutTweener?.Kill();
            //fadeOutTweener = null;
            //fadeInTweener?.Kill();
            //fadeInTweener = null;

            //m_fadeInPercent = 0;
            //m_fadeInOut = false;
            //m_currentMovieTotalTime = 0;
            //m_fadeDuration = 0;
            //m_fadeOutTime = 0;
        }

        /// <summary>
        /// 没有进池子，直接Destory掉的情况
        /// </summary>
        public virtual void Dispose()
        {
            if (_playVideoTaskSource != null)
            {
                _playVideoTaskSource.TrySetCanceled();
                _playVideoTaskSource = null;
            }

            if (_rawVideoPlayer != null)
            {
                GameObject.Destroy(_rawVideoPlayer.gameObject);
                _rawVideoPlayer = null;
            }

        }
    }
}
